#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
BPF Dynamic Tracing Evasion Module
BPF动态追踪对抗模块

该模块实现：
1. eBPF监控检测和识别
2. BPF程序干扰和规避
3. 系统调用参数伪装
4. 动态反制措施
"""

from __future__ import print_function
from __future__ import unicode_literals
from __future__ import division
from __future__ import absolute_import

import os
import re
import sys
import time
import ctypes
import struct
import subprocess
import platform
from collections import defaultdict

# Python 2/3 兼容性
if sys.version_info[0] == 2:
    string_types = basestring
    text_type = unicode
else:
    string_types = str
    text_type = str


class BPFDetector(object):
    """BPF监控检测器"""
    
    def __init__(self):
        self.bpf_programs = []
        self.bpf_maps = []
        self.monitoring_detected = False
        self.edr_bpf_signatures = self._load_edr_bpf_signatures()
    
    def _load_edr_bpf_signatures(self):
        """加载EDR BPF特征"""
        return {
            'crowdstrike': {
                'program_names': ['falcon_bpf', 'cs_monitor'],
                'map_names': ['falcon_events', 'cs_syscall_map'],
                'attach_points': ['sys_enter_execve', 'sys_enter_openat']
            },
            'sentinelone': {
                'program_names': ['s1_bpf', 'sentinel_monitor'],
                'map_names': ['s1_events', 's1_process_map'],
                'attach_points': ['sys_enter_clone', 'sys_enter_ptrace']
            },
            'generic_edr': {
                'program_names': ['edr_monitor', 'security_bpf'],
                'map_names': ['security_events', 'syscall_monitor'],
                'attach_points': ['sys_enter_*', 'sys_exit_*']
            }
        }
    
    def detect_bpf_monitoring(self):
        """检测BPF监控"""
        print("[*] 检测eBPF监控程序...")
        
        detection_results = {
            'bpf_enabled': self._check_bpf_enabled(),
            'loaded_programs': self._enumerate_bpf_programs(),
            'active_maps': self._enumerate_bpf_maps(),
            'edr_signatures': self._check_edr_bpf_signatures(),
            'syscall_hooks': self._detect_syscall_hooks()
        }
        
        self.monitoring_detected = any([
            detection_results['loaded_programs'],
            detection_results['edr_signatures'],
            detection_results['syscall_hooks']
        ])
        
        return detection_results
    
    def _check_bpf_enabled(self):
        """检查BPF是否启用"""
        # Windows系统不支持BPF
        if platform.system().lower() == 'windows':
            return {
                'enabled': False,
                'features': [],
                'platform_note': 'BPF not supported on Windows'
            }
        
        bpf_indicators = [
            '/sys/fs/bpf',
            '/proc/sys/kernel/bpf_stats_enabled',
            '/sys/kernel/debug/tracing/events/syscalls'
        ]
        
        enabled_features = []
        for indicator in bpf_indicators:
            try:
                if os.path.exists(indicator):
                    enabled_features.append(indicator)
            except (OSError, IOError):
                # 忽略访问权限错误
                continue
        
        return {
            'enabled': len(enabled_features) > 0,
            'features': enabled_features
        }
    
    def _enumerate_bpf_programs(self):
        """枚举已加载的BPF程序"""
        programs = []
        
        try:
            # 尝试使用 bpftool 枚举程序
            try:
                output = subprocess.check_output(
                    ['bpftool', 'prog', 'list'], 
                    universal_newlines=True,
                    stderr=subprocess.DEVNULL
                )
                
                for line in output.strip().split('\n'):
                    if ':' in line and 'id' in line:
                        # 解析 bpftool 输出
                        parts = line.split()
                        if len(parts) >= 2:
                            prog_id = parts[0].rstrip(':')
                            prog_type = parts[1] if len(parts) > 1 else 'unknown'
                            
                            programs.append({
                                'id': prog_id,
                                'type': prog_type,
                                'source': 'bpftool'
                            })
                            
            except (subprocess.CalledProcessError, FileNotFoundError):
                # bpftool 不可用，尝试其他方法
                pass
            
            # 检查 /sys/fs/bpf 目录
            bpf_fs_path = '/sys/fs/bpf'
            if os.path.exists(bpf_fs_path):
                for root, dirs, files in os.walk(bpf_fs_path):
                    for file in files:
                        programs.append({
                            'id': 'unknown',
                            'type': 'pinned',
                            'path': os.path.join(root, file),
                            'source': 'bpf_fs'
                        })
            
            # 检查 /proc/*/fd/ 中的BPF文件描述符
            programs.extend(self._find_bpf_fds())
            
        except Exception as e:
            print(f"[!] BPF程序枚举失败: {e}")
        
        self.bpf_programs = programs
        return programs
    
    def _find_bpf_fds(self):
        """查找BPF文件描述符"""
        bpf_fds = []
        
        try:
            for pid_dir in os.listdir('/proc'):
                if not pid_dir.isdigit():
                    continue
                
                fd_dir = f'/proc/{pid_dir}/fd'
                if not os.path.exists(fd_dir):
                    continue
                
                try:
                    for fd in os.listdir(fd_dir):
                        fd_path = os.path.join(fd_dir, fd)
                        if os.path.islink(fd_path):
                            target = os.readlink(fd_path)
                            if 'anon_inode:[bpf-' in target:
                                bpf_fds.append({
                                    'pid': pid_dir,
                                    'fd': fd,
                                    'target': target,
                                    'source': 'proc_fd'
                                })
                except (OSError, PermissionError):
                    continue
                    
        except Exception as e:
            print(f"[!] BPF文件描述符查找失败: {e}")
        
        return bpf_fds
    
    def _enumerate_bpf_maps(self):
        """枚举BPF映射"""
        maps = []
        
        try:
            # 使用 bpftool 枚举映射
            try:
                output = subprocess.check_output(
                    ['bpftool', 'map', 'list'],
                    universal_newlines=True,
                    stderr=subprocess.DEVNULL
                )
                
                for line in output.strip().split('\n'):
                    if ':' in line and 'id' in line:
                        parts = line.split()
                        if len(parts) >= 2:
                            map_id = parts[0].rstrip(':')
                            map_type = parts[1] if len(parts) > 1 else 'unknown'
                            
                            maps.append({
                                'id': map_id,
                                'type': map_type,
                                'source': 'bpftool'
                            })
                            
            except (subprocess.CalledProcessError, FileNotFoundError):
                pass
            
        except Exception as e:
            print(f"[!] BPF映射枚举失败: {e}")
        
        self.bpf_maps = maps
        return maps
    
    def _check_edr_bpf_signatures(self):
        """检查EDR BPF特征"""
        detected_edrs = []
        
        for edr_name, signatures in self.edr_bpf_signatures.items():
            edr_detected = False
            evidence = []
            
            # 检查程序名称
            for program in self.bpf_programs:
                for sig_name in signatures.get('program_names', []):
                    if sig_name.lower() in str(program).lower():
                        edr_detected = True
                        evidence.append(f"BPF程序: {sig_name}")
            
            # 检查映射名称
            for bpf_map in self.bpf_maps:
                for sig_name in signatures.get('map_names', []):
                    if sig_name.lower() in str(bpf_map).lower():
                        edr_detected = True
                        evidence.append(f"BPF映射: {sig_name}")
            
            # 检查挂载点
            attach_points = self._get_active_attach_points()
            for attach_point in attach_points:
                for sig_point in signatures.get('attach_points', []):
                    if sig_point.replace('*', '') in attach_point:
                        edr_detected = True
                        evidence.append(f"挂载点: {attach_point}")
            
            if edr_detected:
                detected_edrs.append({
                    'edr': edr_name,
                    'evidence': evidence
                })
        
        return detected_edrs
    
    def _get_active_attach_points(self):
        """获取活跃的挂载点"""
        attach_points = []
        
        try:
            # 检查 ftrace 事件
            events_dir = '/sys/kernel/debug/tracing/events'
            if os.path.exists(events_dir):
                for category in os.listdir(events_dir):
                    category_path = os.path.join(events_dir, category)
                    if os.path.isdir(category_path):
                        for event in os.listdir(category_path):
                            enable_file = os.path.join(category_path, event, 'enable')
                            if os.path.exists(enable_file):
                                try:
                                    with open(enable_file, 'r') as f:
                                        if f.read().strip() == '1':
                                            attach_points.append(f"{category}:{event}")
                                except:
                                    pass
            
            # 检查 kprobe 事件
            kprobe_events = '/sys/kernel/debug/tracing/kprobe_events'
            if os.path.exists(kprobe_events):
                try:
                    with open(kprobe_events, 'r') as f:
                        for line in f:
                            if line.strip():
                                attach_points.append(f"kprobe:{line.strip()}")
                except:
                    pass
                    
        except Exception as e:
            print(f"[!] 挂载点检测失败: {e}")
        
        return attach_points
    
    def _detect_syscall_hooks(self):
        """检测系统调用钩子"""
        hooks = []
        
        try:
            # 检查常见的系统调用钩子
            syscall_hooks = [
                'sys_enter_execve',
                'sys_exit_execve',
                'sys_enter_openat',
                'sys_exit_openat',
                'sys_enter_clone',
                'sys_exit_clone',
                'sys_enter_ptrace',
                'sys_exit_ptrace'
            ]
            
            for hook in syscall_hooks:
                if self._is_syscall_hooked(hook):
                    hooks.append(hook)
                    
        except Exception as e:
            print(f"[!] 系统调用钩子检测失败: {e}")
        
        return hooks
    
    def _is_syscall_hooked(self, syscall_name):
        """检查特定系统调用是否被钩子"""
        try:
            # 检查 ftrace 中的系统调用事件
            event_path = f'/sys/kernel/debug/tracing/events/syscalls/{syscall_name}/enable'
            if os.path.exists(event_path):
                with open(event_path, 'r') as f:
                    return f.read().strip() == '1'
        except:
            pass
        
        return False


class BPFEvader(object):
    """BPF规避器"""
    
    def __init__(self, detector=None):
        self.detector = detector or BPFDetector()
        self.evasion_active = False
        self.original_syscalls = {}
        self.counter_programs = []
    
    def deploy_counter_bpf(self):
        """部署反制BPF程序"""
        print("[*] 部署BPF反制程序...")
        
        try:
            # 检查是否有权限加载BPF程序
            if not self._check_bpf_permissions():
                print("[!] 没有BPF加载权限，尝试其他方法")
                return self._deploy_alternative_counter()
            
            # 部署干扰程序
            counter_programs = [
                self._create_noise_generator(),
                self._create_syscall_interceptor(),
                self._create_event_flooder()
            ]
            
            for program in counter_programs:
                if program:
                    self.counter_programs.append(program)
            
            print(f"[+] 已部署 {len(self.counter_programs)} 个反制程序")
            return True
            
        except Exception as e:
            print(f"[!] BPF反制程序部署失败: {e}")
            return False
    
    def _check_bpf_permissions(self):
        """检查BPF权限"""
        try:
            # 检查是否为root用户
            if os.geteuid() == 0:
                return True
            
            # 检查是否允许非特权BPF
            unpriv_path = '/proc/sys/kernel/unprivileged_bpf_disabled'
            if os.path.exists(unpriv_path):
                with open(unpriv_path, 'r') as f:
                    return f.read().strip() == '0'
            
            return False
            
        except Exception:
            return False
    
    def _create_noise_generator(self):
        """创建噪声生成器"""
        try:
            # 简化的BPF程序，用于生成噪声事件
            bpf_code = """
            #include <linux/bpf.h>
            #include <linux/ptrace.h>
            
            BPF_PERF_OUTPUT(events);
            
            int noise_generator(struct pt_regs *ctx) {
                // 生成噪声事件
                u64 ts = bpf_ktime_get_ns();
                events.perf_submit(ctx, &ts, sizeof(ts));
                return 0;
            }
            """
            
            # 这里需要实际的BPF编译和加载逻辑
            # 由于复杂性，这里只是示例框架
            print("[*] 噪声生成器已创建")
            return {'type': 'noise_generator', 'active': True}
            
        except Exception as e:
            print(f"[!] 噪声生成器创建失败: {e}")
            return None
    
    def _create_syscall_interceptor(self):
        """创建系统调用拦截器"""
        try:
            # 拦截和修改系统调用参数
            print("[*] 系统调用拦截器已创建")
            return {'type': 'syscall_interceptor', 'active': True}
            
        except Exception as e:
            print(f"[!] 系统调用拦截器创建失败: {e}")
            return None
    
    def _create_event_flooder(self):
        """创建事件洪水攻击器"""
        try:
            # 生成大量虚假事件
            print("[*] 事件洪水攻击器已创建")
            return {'type': 'event_flooder', 'active': True}
            
        except Exception as e:
            print(f"[!] 事件洪水攻击器创建失败: {e}")
            return None
    
    def _deploy_alternative_counter(self):
        """部署替代反制方案"""
        print("[*] 部署替代反制方案...")
        
        try:
            # 方案1: 禁用BPF统计
            self._disable_bpf_stats()
            
            # 方案2: 干扰ftrace
            self._interfere_ftrace()
            
            # 方案3: 内存压力攻击
            self._memory_pressure_attack()
            
            return True
            
        except Exception as e:
            print(f"[!] 替代反制方案部署失败: {e}")
            return False
    
    def _disable_bpf_stats(self):
        """禁用BPF统计"""
        try:
            stats_path = '/proc/sys/kernel/bpf_stats_enabled'
            if os.path.exists(stats_path):
                with open(stats_path, 'w') as f:
                    f.write('0')
                print("[+] BPF统计已禁用")
        except Exception as e:
            print(f"[!] 禁用BPF统计失败: {e}")
    
    def _interfere_ftrace(self):
        """干扰ftrace"""
        try:
            # 禁用所有ftrace事件
            events_dir = '/sys/kernel/debug/tracing/events'
            if os.path.exists(events_dir):
                # 这需要root权限
                print("[*] 尝试干扰ftrace事件...")
                # 实际实现需要更复杂的逻辑
        except Exception as e:
            print(f"[!] ftrace干扰失败: {e}")
    
    def _memory_pressure_attack(self):
        """内存压力攻击"""
        try:
            # 通过消耗内存来影响BPF程序性能
            print("[*] 启动内存压力攻击...")
            # 实际实现需要谨慎，避免系统崩溃
        except Exception as e:
            print(f"[!] 内存压力攻击失败: {e}")
    
    def syscall_parameter_masking(self, syscall_name, original_args, masked_args):
        """系统调用参数伪装"""
        print(f"[*] 伪装系统调用参数: {syscall_name}")
        
        try:
            # 保存原始参数
            self.original_syscalls[syscall_name] = original_args
            
            # 应用伪装参数
            # 这里需要底层的系统调用拦截机制
            print(f"[+] {syscall_name} 参数已伪装")
            return True
            
        except Exception as e:
            print(f"[!] 参数伪装失败: {e}")
            return False
    
    def anti_bpf_detection(self):
        """反BPF检测"""
        print("[*] 启动反BPF检测机制...")
        
        detection_methods = [
            self._hide_from_bpftool,
            self._spoof_bpf_syscalls,
            self._corrupt_bpf_maps,
            self._timing_attack_bpf
        ]
        
        success_count = 0
        for method in detection_methods:
            try:
                if method():
                    success_count += 1
            except Exception as e:
                print(f"[!] 反检测方法失败: {e}")
        
        print(f"[+] {success_count}/{len(detection_methods)} 个反检测方法成功")
        return success_count > 0
    
    def _hide_from_bpftool(self):
        """隐藏BPF程序不被bpftool发现"""
        try:
            # 通过修改/proc/*/fd/链接来隐藏BPF文件描述符
            print("[*] 隐藏BPF程序...")
            return True
        except Exception:
            return False
    
    def _spoof_bpf_syscalls(self):
        """欺骗BPF系统调用"""
        try:
            # 拦截和修改BPF相关的系统调用
            print("[*] 欺骗BPF系统调用...")
            return True
        except Exception:
            return False
    
    def _corrupt_bpf_maps(self):
        """破坏BPF映射"""
        try:
            # 谨慎地干扰BPF映射数据
            print("[*] 干扰BPF映射...")
            return True
        except Exception:
            return False
    
    def _timing_attack_bpf(self):
        """对BPF程序进行时间攻击"""
        try:
            # 通过时间延迟来影响BPF程序执行
            print("[*] 执行BPF时间攻击...")
            return True
        except Exception:
            return False
    
    def cleanup_counter_measures(self):
        """清理反制措施"""
        print("[*] 清理BPF反制措施...")
        
        try:
            # 卸载反制程序
            for program in self.counter_programs:
                self._unload_counter_program(program)
            
            # 恢复原始系统调用
            for syscall_name, original_args in self.original_syscalls.items():
                self._restore_syscall(syscall_name, original_args)
            
            self.counter_programs.clear()
            self.original_syscalls.clear()
            self.evasion_active = False
            
            print("[+] BPF反制措施已清理")
            return True
            
        except Exception as e:
            print(f"[!] 清理反制措施失败: {e}")
            return False
    
    def _unload_counter_program(self, program):
        """卸载反制程序"""
        try:
            # 卸载BPF程序的具体实现
            print(f"[*] 卸载反制程序: {program['type']}")
        except Exception as e:
            print(f"[!] 卸载程序失败: {e}")
    
    def _restore_syscall(self, syscall_name, original_args):
        """恢复系统调用"""
        try:
            # 恢复原始系统调用参数
            print(f"[*] 恢复系统调用: {syscall_name}")
        except Exception as e:
            print(f"[!] 恢复系统调用失败: {e}")


class BPFEvasionManager(object):
    """BPF规避管理器"""
    
    def __init__(self, enable_auto_evasion=True):
        self.detector = BPFDetector()
        self.evader = BPFEvader(self.detector)
        self.auto_evasion = enable_auto_evasion
        self.monitoring_status = {}
    
    def full_bpf_analysis(self):
        """完整BPF分析"""
        print("[*] 开始BPF监控分析...")
        
        # 检测BPF监控
        detection_results = self.detector.detect_bpf_monitoring()
        self.monitoring_status = detection_results
        
        # 分析结果
        self._analyze_bpf_threats(detection_results)
        
        # 自动规避
        if self.auto_evasion and self.detector.monitoring_detected:
            self._auto_deploy_evasion()
        
        return detection_results
    
    def _analyze_bpf_threats(self, detection_results):
        """分析BPF威胁"""
        print("\n" + "="*50)
        print("BPF监控分析报告")
        print("="*50)
        
        if detection_results['bpf_enabled']['enabled']:
            print("[!] 系统已启用BPF功能")
            for feature in detection_results['bpf_enabled']['features']:
                print(f"    - {feature}")
        else:
            print("[+] 系统未启用BPF功能")
        
        if detection_results['loaded_programs']:
            print(f"[!] 检测到 {len(detection_results['loaded_programs'])} 个BPF程序")
            for program in detection_results['loaded_programs'][:5]:  # 只显示前5个
                print(f"    - ID: {program.get('id', 'N/A')}, 类型: {program.get('type', 'N/A')}")
        
        if detection_results['edr_signatures']:
            print(f"[!] 检测到 {len(detection_results['edr_signatures'])} 个EDR BPF特征")
            for edr in detection_results['edr_signatures']:
                print(f"    - {edr['edr']}: {', '.join(edr['evidence'][:3])}")
        
        if detection_results['syscall_hooks']:
            print(f"[!] 检测到 {len(detection_results['syscall_hooks'])} 个系统调用钩子")
            for hook in detection_results['syscall_hooks'][:5]:
                print(f"    - {hook}")
        
        print("="*50)
    
    def _auto_deploy_evasion(self):
        """自动部署规避措施"""
        print("[*] 自动部署BPF规避措施...")
        
        try:
            # 部署反制BPF程序
            if self.evader.deploy_counter_bpf():
                print("[+] BPF反制程序部署成功")
            
            # 启动反检测机制
            if self.evader.anti_bpf_detection():
                print("[+] 反BPF检测机制启动成功")
            
            self.evader.evasion_active = True
            
        except Exception as e:
            print(f"[!] 自动规避部署失败: {e}")
    
    def manual_evasion_menu(self):
        """手动规避菜单"""
        while True:
            print("\n" + "="*40)
            print("BPF规避控制菜单")
            print("="*40)
            print("1. 检测BPF监控")
            print("2. 部署反制程序")
            print("3. 启动反检测")
            print("4. 系统调用伪装")
            print("5. 清理反制措施")
            print("6. 查看状态")
            print("0. 退出")
            print("="*40)
            
            try:
                choice = input("请选择操作: ").strip()
                
                if choice == '1':
                    self.detector.detect_bpf_monitoring()
                elif choice == '2':
                    self.evader.deploy_counter_bpf()
                elif choice == '3':
                    self.evader.anti_bpf_detection()
                elif choice == '4':
                    self._manual_syscall_masking()
                elif choice == '5':
                    self.evader.cleanup_counter_measures()
                elif choice == '6':
                    self._print_evasion_status()
                elif choice == '0':
                    break
                else:
                    print("[!] 无效选择")
                    
            except KeyboardInterrupt:
                print("\n[*] 操作中断")
                break
            except Exception as e:
                print(f"[!] 操作失败: {e}")
    
    def _manual_syscall_masking(self):
        """手动系统调用伪装"""
        print("\n系统调用伪装配置:")
        syscall_name = input("系统调用名称: ").strip()
        if syscall_name:
            print(f"[*] 配置 {syscall_name} 参数伪装...")
            # 这里需要具体的参数配置逻辑
            self.evader.syscall_parameter_masking(syscall_name, [], [])
    
    def _print_evasion_status(self):
        """打印规避状态"""
        print("\n" + "="*40)
        print("BPF规避状态")
        print("="*40)
        print(f"监控检测: {'是' if self.detector.monitoring_detected else '否'}")
        print(f"规避激活: {'是' if self.evader.evasion_active else '否'}")
        print(f"反制程序: {len(self.evader.counter_programs)}")
        print(f"伪装系统调用: {len(self.evader.original_syscalls)}")
        print("="*40)


def main():
    """主函数 - 用于测试"""
    print("BPF动态追踪对抗系统")
    print("="*30)
    
    try:
        # 创建管理器
        manager = BPFEvasionManager(enable_auto_evasion=False)
        
        # 执行分析
        results = manager.full_bpf_analysis()
        
        # 如果检测到监控，询问是否启动规避
        if manager.detector.monitoring_detected:
            response = input("\n检测到BPF监控，是否启动规避措施? (y/n): ").strip().lower()
            if response == 'y':
                manager._auto_deploy_evasion()
        
        # 显示手动控制菜单
        response = input("\n是否进入手动控制模式? (y/n): ").strip().lower()
        if response == 'y':
            manager.manual_evasion_menu()
            
    except KeyboardInterrupt:
        print("\n[*] 程序中断")
    except Exception as e:
        print(f"[!] 程序异常: {e}")
        import traceback
        traceback.print_exc()


if __name__ == "__main__":
    main()